package se.study.algorithm;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

/** *//** 
* RSA安全编码组件 
*   
* @version 1.0 
* @since 1.0 
*/ 
public abstract class RSAUtil extends RSACoder {   
    public static final String KEY_ALGORITHM = "RSA";   
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";   

    private static final String PUBLIC_KEY = "RSAPublicKey";   
    private static final String PRIVATE_KEY = "RSAPrivateKey";   

    /** *//** 
     * 用私钥对信息生成数字签名 
     *   
     * @param data 
     *            加密数据 
     * @param privateKey 
     *            私钥 
     *   
     * @return 
     * @throws Exception 
     */ 
    public static String sign(byte[] data, String privateKey) throws Exception {   
        // 解密由base64编码的私钥   
        byte[] keyBytes = decryptBASE64(privateKey);   

        // 构造PKCS8EncodedKeySpec对象   
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);   

        // KEY_ALGORITHM 指定的加密算法   
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);   

        // 取私钥匙对象   
        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);   

        // 用私钥对信息生成数字签名   
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);   
        signature.initSign(priKey);   
        signature.update(data);   

        return encryptBASE64(signature.sign());   
    }   

    /** *//** 
     * 校验数字签名 
     *   
     * @param data 
     *            加密数据 
     * @param publicKey 
     *            公钥 
     * @param sign 
     *            数字签名 
     *   
     * @return 校验成功返回true 失败返回false 
     * @throws Exception 
     *   
     */ 
    public static boolean verify(byte[] data, String publicKey, String sign)   
            throws Exception {   

        // 解密由base64编码的公钥   
        byte[] keyBytes = decryptBASE64(publicKey);   

        // 构造X509EncodedKeySpec对象   
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);   

        // KEY_ALGORITHM 指定的加密算法   
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);   

        // 取公钥匙对象   
        PublicKey pubKey = keyFactory.generatePublic(keySpec);   

        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);   
        signature.initVerify(pubKey);   
        signature.update(data);   

        // 验证签名是否正常   
        return signature.verify(decryptBASE64(sign));   
    }   

    /** *//** 
     * 解密<br> 
     *   
     * @param data 
     * @param key 
     * @return 
     * @throws Exception 
     */ 
    public static byte[] decryptByPrivateKey(byte[] data, String key)   
            throws Exception {   
        // 对密钥解密   
        byte[] keyBytes = decryptBASE64(key);   

        // 取得私钥   
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);   
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);   
        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);   

        // 对数据解密   
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());   
        cipher.init(Cipher.DECRYPT_MODE, privateKey);   

        return cipher.doFinal(data);   
    }   
    /** *//** 
     * 解密<br> 
     * 用私钥解密 http://www.5a520.cn http://www.feng123.com 
     *   
     * @param data 
     * @param key 
     * @return 
     * @throws Exception 
     */
    public static byte[] decryptByPrivateKey(String encodedData,String privateKey) throws Exception{
   	   byte[] decodedData = decryptByPrivateKey(encodedData.getBytes(), privateKey);  
   	   return decodedData;
    }
   
    /** *//** 
     * 解密<br> 
     * 用私钥解密 
     *   
     * @param data 
     * @param key 
     * @return 
     * @throws Exception 
     */ 
    public static byte[] decryptByPublicKey(byte[] data, String key)   
            throws Exception {   
        // 对密钥解密   
        byte[] keyBytes = decryptBASE64(key);   

        // 取得公钥   
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);   
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);   
        Key publicKey = keyFactory.generatePublic(x509KeySpec);   

        // 对数据解密   
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());   
        cipher.init(Cipher.DECRYPT_MODE, publicKey);   

        return cipher.doFinal(data);   
    }   
    /** *//** 
     * 解密<br> 
     * 用私钥解密 
     *   
     * @param data 
     * @param key 
     * @return 
     * @throws Exception 
     */ 
    public static byte[] decryptByPublicKey(String data,String publicKey) throws Exception{
	   	byte[] decodedData = decryptByPublicKey(data.getBytes(), publicKey);  
	   	return decodedData;
	}
    
    /** *//** 
     * 加密<br> 
     * 用私钥加密 
     *   
     * @param data 
     * @param key 
     * @return 
     * @throws Exception 
     */ 
    public static byte[] encryptByPrivateKey(byte[] data, String key)   
            throws Exception {   
        // 对密钥解密   
        byte[] keyBytes = decryptBASE64(key);   

        // 取得私钥   
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);   
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);   
        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);   

        // 对数据加密   
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());   
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);   

        return cipher.doFinal(data);   
    }   
    /** *//** 
     * 加密<br> 
     * 用私钥加密 
     *   
     * @param data 
     * @param key 
     * @return 
     * @throws Exception 
     */ 
    public static byte[] encryptByPrivateKey(String data, String key) throws Exception{
    	return encryptByPrivateKey(data.getBytes(), key);
    }
    
    /** *//** 
     * 加密<br> 
     * 用公钥加密 
     *   
     * @param data 
     * @param key 
     * @return 
     * @throws Exception 
     */ 
    public static byte[] encryptByPublicKey(byte[] data, String key)   
            throws Exception {   
        // 对公钥解密   
        byte[] keyBytes = decryptBASE64(key);   

        // 取得公钥   
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);   
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);   
        Key publicKey = keyFactory.generatePublic(x509KeySpec);   

        // 对数据加密   
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());   
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);   

        return cipher.doFinal(data);   
    }   

    /** *//** 
     * 加密<br> 
     * 用公钥加密 
     *   
     * @param data 
     * @param key 
     * @return 
     * @throws Exception 
     */ 
    public static byte[] encryptByPublicKey(String data, String key) throws Exception{
    	return encryptByPublicKey(data.getBytes(), key);
    }
    
    public static String byte2String(byte[] data){
    	if (data == null)
    		return null;
    	return new String(data);
    }
    /** *//** 
     * 取得私钥 
     *   
     * @param keyMap 
     * @return 
     * @throws Exception 
     */ 
    public static String getPrivateKey(Map<String, Object> keyMap)   
            throws Exception {   
        Key key = (Key) keyMap.get(PRIVATE_KEY);   

        return encryptBASE64(key.getEncoded());   
    }   

    /** *//** 
     * 取得公钥 
     *   
     * @param keyMap 
     * @return 
     * @throws Exception 
     */ 
    public static String getPublicKey(Map<String, Object> keyMap)   
            throws Exception {   
        Key key = (Key) keyMap.get(PUBLIC_KEY);   

        return encryptBASE64(key.getEncoded());   
    }   

    /** *//** 
     * 初始化密钥 
     *   
     * @return 
     * @throws Exception 
     */ 
    public static Map<String, Object> initKey() throws Exception {   
        KeyPairGenerator keyPairGen = KeyPairGenerator   
                .getInstance(KEY_ALGORITHM);   
        keyPairGen.initialize(1024);   

        KeyPair keyPair = keyPairGen.generateKeyPair();   

        // 公钥   
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();   

        // 私钥   
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   

        Map<String, Object> keyMap = new HashMap<String, Object>(2);   

        keyMap.put(PUBLIC_KEY, publicKey);   
        keyMap.put(PRIVATE_KEY, privateKey);   
        return keyMap;   
    }   
    
    public static String bytesToHexString(byte[] src){       
        StringBuilder stringBuilder = new StringBuilder();       
        if (src == null || src.length <= 0) {       
            return null;       
        }       
        for (int i = 0; i < src.length; i++) {       
            int v = src[i] & 0xFF;       
            String hv = Integer.toHexString(v);       
            if (hv.length() < 2) {       
                stringBuilder.append(0);       
            }       
            stringBuilder.append(hv);       
        }       
        return stringBuilder.toString();       
    }

    public static byte[] hex2Byte(String hex) {  
        String digital = "0123456789ABCDEF";  
        char[] hex2char = hex.toCharArray();  
        byte[] bytes = new byte[hex.length() / 2];  
        int temp;  
        for (int i = 0; i < bytes.length; i++) {  
        // 其实和上面的函数是一样的 multiple 16 就是右移4位 这样就成了高4位了  
        // 然后和低四位相加， 相当于 位操作"|"   
        //相加后的数字 进行 位 "&" 操作 防止负数的自动扩展. {0xff byte最大表示数}  
            temp = digital.indexOf(hex2char[2 * i]) * 16;  
            temp += digital.indexOf(hex2char[2 * i + 1]);  
            bytes[i] = (byte) (temp & 0xff);  
        }  
        return bytes;  
    } 
    public static void main(String[] args) throws Exception {
    	 String data = "測試加密";
    	 // 加密字符串
    	 byte[] encodedData = encryptByPublicKey(data, Constants.RSA_PUBLIC_KEY);
    	 // 转换为16进制
    	 String hex = bytesToHexString(encodedData).toUpperCase();
    	 
    	 // .....传输.....
    	 
    	 // 反解密16进制
    	 byte[] unHex = hex2Byte(hex);
    	 // 解密数据
    	 byte[] decodedData = decryptByPrivateKey(unHex, Constants.RSA_PRIVATE_KEY);
    	 
    	 String decodedDataStr = byte2String(decodedData);
    	 System.out.println("加密后："+byte2String(encodedData));
    	 System.out.println("解密后："+decodedDataStr);
//    	 String x16 = "3F021BF71D56B1B9129B50D45D231BBCE223F9F3B89BCA57E060C423562B7C7F913099E3A55C2B1F2B44ECF89289335DCEF60784EA2F99C5D1CE334C66701DCC439D3A2591DD77EDE3087E2C6687556CF6AA025DEF6F8187B42A3894D6E45ED2995B13ED9C9407E5A31644F309C078734D65D4563078808FE13F6AD65D9DD9F4";
//    	 byte[] decodedData2 = decryptByPrivateKey(hex2Byte(x16), Constants.RSA_PRIVATE_KEY);
//    	 System.out.println(new String(decodedData2));
	}
    
    
   
} 
